﻿#define _CRT_SECURE_NO_WARNINGS


#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>//断言



//字符分类函数
//int main()
//{
//	if (islower('a'))//判断：是小写字母a-z返回真
//		printf("c\n");
//		printf("%d\n",islower('c'));//返回值2?,不管
//	if (isspace(' '))//判断：是空白返回真
//		printf("%d\n", 1);
//		printf("%d\n", isspace(' '));//……
//	return 0;
//}//注意()里是单引号

//字符转换函数
//将大写字母转换为小写字母，小写字母不变：tolower
//将小写字母转换为大写字母，大写字母不变：toupper
//int main()
//{
//	char arr[] = "i Am A StuDenT";//
//	char* a = arr;
//	while (*a != '\0')
//	{
//		if (islower(*a))
//		{
//			*a = toupper(*a);
//		}
//		a++;
//	}
//	printf("%s\n", arr);
//	return 0;
//}



//strlen函数的使用和模拟实现
//使用和理解
//int main()
//{
//	const char* str1 = "abcdef";
//	const char* str2 = "bbb";
//	if (strlen(str2) - strlen(str1) > 0)//strlen函数返回值是size_t类型的，两个size_t类型相减还是size_t类型
//		//size_t类型的数是大于0的
//	{
//		printf("str2>str1\n\n");//返回>
//	}
//	else
//	{
//		printf("srt1>str2\n\n");
//	}
//
//
//	//验证
//	size_t a = 1;
//	size_t b = 2;
//	printf("a-b=%zd\n", a - b);//a-b返回值是-1，但是是size_t类型的
//	if (a - b > 0)
//		printf("a>b\n\n");//返回值是>，但由上述知道a-b的值为-1
//	//但是还是>0，因此我们可以知道，size_t类型的数在计算机理解上是>0的
//	else
//		printf("a<b\n\n");
//
//	//验证上述结论
//	size_t c = -1;
//	printf("c  =%zd\n", c);//打印的c的值为-1
//	if (c > 0)
//		printf("c>0\n\n");//但是判断还是c>0
//	else
//		printf("c<0\n\n");//因为c的类型为size_t类型，计算机自动判断为大于0
//
//	return 0;
//}
//实现
//int my_strlen1(char* s)
//{
//	int count = 0;
//	assert(s);//这里是确保s不为空指针
//	while (*s)//直接*s就可以，或者*s != '\0'
//	{
//		count++;
//		s++;
//	}
//	return count;
//}
//int my_strlen2(char* s)
//{
//	assert(s);
//	if (*s == '\0')
//		return 0;
//	else
//		return 1 + my_strlen2(s+1);
//}
//int my_strlen3(char* s)
//{
//	assert(s);
//	char* p = s;
//	while (*s)
//		s++;
//	return s - p;
//}
//int main()
//{
//	char arr[] = "abcd";
//
//	printf("%d\n", my_strlen1(arr));//计数器
//
//	printf("%d\n", my_strlen2(arr));//函数递归
//
//	printf("%d\n", my_strlen3(arr));//指针-指针
//
//	return 0;
//}




//函数strcpy，将一个字符串复制到另一个字符串中
//char* strcpy(char* destination, const char* source);
//char* my_strcpy(char* dest, const char* scr)
//{
//	//dest = NULL;检验下面对于断言的理解
//	assert(dest && scr);//断言，效果相当于dest!=NULL  scr!=NULL
//	while (*dest++ = *scr++);//简单重复，当 *dest++ = '\0' 会检测直接停止
//
//	//检验上述对于while中停止的理解
//	char a = '*';
//	while (a = '\0')
//		printf("停止\n");//并未打印，可验证当while中的语句为\0时会停止
//	//调试中a的值为\0，可以验证\0也是传过去了
//}
//int main()
//{
//	char arr1[] = "abcd";
//	char arr2[20] = "****************";
//
//	//strcpy(arr2, arr1);
//	//printf("%s\n", arr2);//这里arr2中储存的字符串是abcd
//
//	my_strcpy(arr2, arr1);
//	printf("%s\n", arr2);//这里arr2中储存的字符串是abcd
//
//	return 0;
//}



//strcat函数用来连接字符串
//char* strcat(char* destination, const char* source);
//char* my_strcat(char* dest, const char* scr)
//{
//	assert(dest && scr);
//	while (*dest++);
//	dest--;
//	while (*dest++ = *scr++);
//}
//int main()
//{
//	char arr1[20] = "abc";
//	char arr2[] = "def";
//
//	strcat(arr1, arr2);
//	printf("%s\n", arr1);//打印结果为abcdef
//
//	my_strcat(arr1, arr2);
//	printf("%s\n", arr1);//打印结果为abcdefdef，效果与strcat相同
//
//	return 0;
//}



//strcmp比较两个字符串的大小，分别从两个字符串的第一个字母开始一一对比，按照a-z(对应的ASCII码值)的大小
//例如abc与abd，d>c，abd大返回1
//int strcmp(const char* str1, const char* str2);
//int my_strcmp(const char* str1, const char* str2)
//{
//	assert(str1 && str2);
//	while (*str1 == *str2)
//	{
//		if (*str1 == '\0')//判断，如果*str1==*str2=='\0'，明显是相等的
//			return 0;
//		str1++;
//		str2++;
//	}
//	return *str1 - *str2;//返回的整型的符号与之一致
//}
//int main()
//{
//	char arr1[] = "abcde";
//	char arr2[] = "abcdef";
//
//	printf("%d\n", strcmp(arr1, arr1));
//	printf("%d\n", strcmp(arr1, arr2));
//	printf("%d\n", strcmp(arr2, arr1));
//
//	printf("%d\n", my_strcmp(arr1, arr1));
//	printf("%d\n", my_strcmp(arr1, arr2));
//	printf("%d\n", my_strcmp(arr2, arr1));
//
//	return 0;
//}



//strncpy，效果同strcpy，但是多了一个输入值，可以限制要复制的字符个数
//char * strncpy ( char * destination, const char * source, size_t num );
//char* my_strncpy(char* dest, const char* scr, size_t n)
//{
//	assert(dest && scr);
//	for (int i = 0; i < n; i++)
//		*dest++ = *scr++;
//}
//int main()
//{
//	char arr1[] = "abc";
//	char arr2[10] = "****";//写满10个后面就没有\0了，没有定义的会自动补充为\0
//
//	printf("%s\n", arr2);
//
//	strncpy(arr2, arr1, 1);
//	printf("%s\n", arr2);
//
//	my_strncpy(arr2, arr1, 2);//简单复现
//	printf("%s\n", arr2);
//
//	return 0;
//}



//strncat
//char * strncat ( char * destination, const char * source, size_t num );
//char* my_strncat(char* dest, char* scr, size_t n)
//{
//	assert(dest && scr);
//	while (*dest++);
//	dest--;
//	for (int i = 0; i < n; i++)
//		*dest++ = *scr++;
//}
//int main()
//{
//	char arr1[10] = "abc";
//	char arr2[] = "def";
//
//	printf("%s\n", arr1);
//
//	strncat(arr1, arr2, 1);
//	printf("%s\n", arr1);
//
//	my_strncat(arr1, arr2, 3);//简单复现
//	printf("%s\n", arr1);
//
//	return 0;
//}



//strncmp
//int strncmp ( const char * str1, const char * str2, size_t num );
//int my_strncmp(const char* str1, const char* str2, size_t n)
//{
//	assert(str1 && str2);
//	for (int i = 1; i < n; i++)
//	{
//		if (*str1 == '\0' && *str2 == '\0')
//			return 0;
//		str1++;
//		str2++;
//	}
//	return *str1 - *str2;
//}
//int main()
//{
//	char arr1[] = "abcde";
//	char arr2[] = "abcdef";
//
//	printf("%d\n", strncmp(arr1, arr2, 1));
//	printf("%d\n", strncmp(arr1, arr2, 5));
//	printf("%d\n", strncmp(arr1, arr2, 6));
//
//	printf("%d\n", my_strncmp(arr1, arr2, 1));//简单复现
//	printf("%d\n", my_strncmp(arr1, arr2, 5));
//	printf("%d\n", my_strncmp(arr1, arr2, 6));
//
//	return 0;
//}



//strstr
//const char * strstr ( const char * str1, const char * str2 );
//		char * strstr (		  char * str1, const char * str2 );
const char* my_strstr(const char* s1, const char* s2)
{
	//if (*s2 == NULL)
	//	return s1;
	//要使效果与strstr一样加上这个就行了
	while (*s1)
	{
		
		if (*s1 == *s2)
		{
			char* s3 = s1;
			char* s4 = s2;
			while (*s3++ == *s4++)
			{
				if (*s4 == '\0')
					return s1;
			}
		}
		s1++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcccde";
	char arr2[] = "";

	printf("%s\n", strstr(arr1, arr2));
	//在这里我发现一个问题，就是当arr2中字符为空(null)，就是不包含空格等
	//strstr会直接返回arr1，而不是返回(null)，明显是设定时的不足
	//但我自己编写的是会返回(null)

	printf("%s\n", my_strstr(arr1, arr2));

	return 0;
}



//strtok
//char * strtok ( char * str, const char * delimiters );
//char* my_strtok(char* s, const char* dmt)
//{
//	static char* p = NULL;
//	if(s)
//	{
//		p = s;
//	}
//	if(p==NULL)
//		return NULL;
//	char* left = p;
//	while (*p)
//	{
//		for (int i = strlen(dmt) - 1; i >= 0; i--)
//		{
//			if (*p == *(dmt + i))
//			{
//				*p = '\0';
//				p++;
//				return left;
//			}
//		}
//		p++;
//	}
//	p = NULL;
//	return left;
//}
//int main()
//{
//	char arr[] = "a.b.cd@ef.1";
//	const char* sep = "@.";
//	char* ret = NULL;
//	//for (ret = strtok(arr, sep); ret != NULL; ret = strtok(NULL, sep))
//	//{
//	//	printf("%s\n", ret);
//	//}
//	for (ret = my_strtok(arr, sep); ret != NULL; ret = my_strtok(NULL, sep))
//	{
//		printf("%s\n", ret);
//	}
//	//printf("%s\n", my_strtok(arr, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//	//printf("%s\n", my_strtok(NULL, sep));
//
//	return 0;
//}



//strerror
#include<errno.h>
//int main()
//{
//	int i = 0;
//	for (i = 0; i <= 10; i++)
//	{
//		printf("%s\n", strerror(i));//举例，打印一些错误码
//	}
//	return 0;
//}
//int main()
//{
//	//fopen以读的形式打开文件的时候，如果文件不存在，就打开失败
//	FILE* pFile;
//	pFile = fopen("unexist.ent", "r");//这里出错了，错在文件不存在，下面打印错误信息
//	if (pFile == NULL)
//		printf("Error opening file unexist.ent: %s\n", strerror(errno));
//	perror("Error opening file unexist.ent");
//	return 0;
//}
//看不懂，但只需要知道strerror函数就可以将错误对应的错误信息字符串的地址返回。
//具体功能看课件
//perror函数打印完参数部分的字符串后，再打印⼀个冒号和⼀个空格，再打印错误信息。
//不是很懂，以后再说